#include "ConfigureViewerWidget.hpp"
#include <qstring.h>
#include <qvariant.h>
#include <qfiledialog.h>
#include "OtherImageLoader.hpp"
#include "ConvertRGBToGrayOperator.hpp"
#include "ConvolutionOperator.hpp"
#include "RefiningOperator.hpp"
#include "HoughTransformationOperator.hpp"
#include "GlobalThresholdOperator.hpp"
#include "LocalThresholdOperator.hpp"
#include "AdaptativeThresholdOperator.hpp"
#include "HysteresisThresholdOperator.hpp"
#include "HoughTransformationOperator.hpp"
#include "BasicThresholdFinder.hpp"
#include "IsoDataThresholdFinder.hpp"
#include "OtsuThresholdFinder.hpp"
#include "MaskTools.hpp"
#include "Tools/Logger.hpp"

#include <iostream>
#define ROBERT_MASK 0
#define PREWITT_MASK 1
#define SOBEL_MASK 2
#define PERSONNAL_MASK 3

#define GLOBAL_THRESHOLD 0
#define LOCAL_THRESHOLD 1
#define ADAPTIVE_THRESHOLD 2
#define HYSTERESIS_THRESHOLD 3

#define BASIC_FINDER 0
#define ISODATA_FINDER 1
#define OTSU_FINDER 2

#define SMALL_CLOSING_WINDOW 0
#define MEDIUM_CLOSING_WINDOW 1
#define LARGE_CLOSING_WINDOW 2

#define POLYGONAL_MODELISATION 0
#define HOUGH_MODELISATION 1

//#define QT_VERSION_33


#define DEFAULT_PATH "/home/cderousier/Desktop/TPImage"

	ConfigureViewerWidget::ConfigureViewerWidget( ):
	QWidget(),
	loadImagePushButton(0),
	thresholdOperatorComboBox(0),
	thresholdFinderComboBox(0),
	maskComboBox(0),
	closingComboBox(0),
	modelisingComboBox(0),
	layout(0),

	imageWidget(0),
	gradiantWidget(0),
	thresholdWidget(0),
	refineWidget(0),
	closeWidget(0),
	modelWidget(0),

	histogramWidget(0),
	gradiantHistogram(0),

	originalImage(0),
	gradiantImage(0),
	thresholdedImage(0),
	refinedImage(0),
	closedImage(0),	
	closedOutlineContainer(0),
	modelizedOutlineContainer(0),

	numberOfMask(0),
	masks(0),

	thresholdOperator(0),
	thresholdFinder(0),
	refineOperator(0),
	convolutionOperator(0),
	linkerOperator(0),
	closingOperator(0),
	modelerOperator(0)
	{
		// Initialisation du bouton de chargement d'image
		loadImagePushButton = new QPushButton( QString("Load n Process"), this );

		// Initialisation des masques de convolution
		maskComboBox = new QComboBox(this);
#ifdef QT_VERSION_33
		maskComboBox->insertItem( QString("Masque de Robert"), ROBERT_MASK );
		maskComboBox->insertItem( QString("Masque de Prewitt"), PREWITT_MASK );
		maskComboBox->insertItem( QString("Masque de Sobel"), SOBEL_MASK );
		maskComboBox->insertItem( QString("Masque utilisateur"), PERSONNAL_MASK );		
		maskComboBox->setCurrentItem(SOBEL_MASK);
#else
		maskComboBox->insertItem( ROBERT_MASK, QString("Masque de Robert"), QVariant(ROBERT_MASK) );
		maskComboBox->insertItem( PREWITT_MASK, QString("Masque de Prewitt"), QVariant(PREWITT_MASK) );
		maskComboBox->insertItem( SOBEL_MASK, QString("Masque de Sobel"), QVariant(SOBEL_MASK) );
		maskComboBox->insertItem( PERSONNAL_MASK, QString("Masque utilisateur"), QVariant(ROBERT_MASK) );
		maskComboBox->setCurrentIndex(SOBEL_MASK);
#endif

		// Initialisation des op�ateurs de seuillage
		thresholdOperatorComboBox = new QComboBox(this);
#ifdef QT_VERSION_33
		thresholdOperatorComboBox->insertItem( QString("Seuillage Global"),GLOBAL_THRESHOLD );
		thresholdOperatorComboBox->insertItem( QString("Seuillage Local"), LOCAL_THRESHOLD );
		thresholdOperatorComboBox->insertItem( QString("Seuillage Adaptative"), ADAPTIVE_THRESHOLD );
		thresholdOperatorComboBox->insertItem( QString("Seuillage Hysteresis"), HYSTERESIS_THRESHOLD );
#else
        	thresholdOperatorComboBox->insertItem( GLOBAL_THRESHOLD, QString("Seuillage Global"), QVariant(GLOBAL_THRESHOLD) );
		thresholdOperatorComboBox->insertItem( LOCAL_THRESHOLD, QString("Seuillage Local"), QVariant(LOCAL_THRESHOLD) );
		thresholdOperatorComboBox->insertItem( ADAPTIVE_THRESHOLD, QString("Seuillage Adaptative"), QVariant(ADAPTIVE_THRESHOLD) );
		thresholdOperatorComboBox->insertItem( HYSTERESIS_THRESHOLD, QString("Seuillage Hysteresis"), QVariant(HYSTERESIS_THRESHOLD) );
#endif

		// Initialisation des d�ecteur de seuil
		thresholdFinderComboBox = new QComboBox(this);
#ifdef QT_VERSION_33
		thresholdFinderComboBox->insertItem( QString("Decteur basic"), BASIC_FINDER );
		thresholdFinderComboBox->insertItem( QString("Decteur IsoData"), ISODATA_FINDER );
		thresholdFinderComboBox->insertItem( QString("Decteur Otsu"), OTSU_FINDER );
#else
        	thresholdFinderComboBox->insertItem( BASIC_FINDER, QString("Decteur basic"), QVariant(BASIC_FINDER) );
		thresholdFinderComboBox->insertItem( ISODATA_FINDER, QString("Decteur IsoData"), QVariant(ISODATA_FINDER) );
		thresholdFinderComboBox->insertItem( OTSU_FINDER, QString("Decteur Otsu"), QVariant(OTSU_FINDER) );
#endif

		// Initialisation de la fenetre de fermeture
		closingComboBox = new QComboBox(this);
#ifdef QT_VERSION_33
		closingComboBox->insertItem( QString("Petite fenetre(5 pixels)"), SMALL_CLOSING_WINDOW );
		closingComboBox->insertItem( QString("Moyenne fenetre(10 pixels)"), MEDIUM_CLOSING_WINDOW );
		closingComboBox->insertItem( QString("Grande fenetre(15 pixels)"), LARGE_CLOSING_WINDOW );
#else
        	closingComboBox->insertItem( SMALL_CLOSING_WINDOW, QString("Petite fenetre(5 pixels)"), QVariant(SMALL_CLOSING_WINDOW) );
		closingComboBox->insertItem( MEDIUM_CLOSING_WINDOW, QString("Moyenne fenetre(10 pixels)"), QVariant(MEDIUM_CLOSING_WINDOW) );
		closingComboBox->insertItem( LARGE_CLOSING_WINDOW, QString("Grande fenetre(15 pixels)"), QVariant(LARGE_CLOSING_WINDOW) );
#endif

		// Initialisation de la modelisation
		modelisingComboBox = new QComboBox(this);
#ifdef QT_VERSION_33
		modelisingComboBox->insertItem( QString("Modelisation polygonal"), POLYGONAL_MODELISATION );
		modelisingComboBox->insertItem( QString("Transformee de Hough"), HOUGH_MODELISATION );		
		modelisingComboBox->setCurrentItem(POLYGONAL_MODELISATION);
#else
		modelisingComboBox->insertItem( POLYGONAL_MODELISATION, QString("Modelisation polygonal"), QVariant(POLYGONAL_MODELISATION) );
		modelisingComboBox->insertItem( HOUGH_MODELISATION, QString("Transformeee de Hough"), QVariant(HOUGH_MODELISATION) );
		modelisingComboBox->setCurrentIndex(POLYGONAL_MODELISATION);
#endif

		// Initialisation du layout
		layout = new QHBoxLayout( this ),
		layout->addWidget( loadImagePushButton );
		layout->addWidget( maskComboBox );
		layout->addWidget( thresholdOperatorComboBox );
		layout->addWidget( thresholdFinderComboBox );
		layout->addWidget( closingComboBox );
		layout->addWidget( modelisingComboBox );

		// Connexion des boutons
		QObject::connect( loadImagePushButton, SIGNAL(clicked()), this, SLOT(CreateImagePipeline()) );

		//QObject::connect( &this, SIGNAL(clicked()), &this, SLOT(quit()) );
	}

	ConfigureViewerWidget::~ConfigureViewerWidget()
	{
		delete loadImagePushButton;
		delete thresholdOperatorComboBox;
		delete thresholdFinderComboBox;
		delete maskComboBox;
		delete closingComboBox;
		delete modelisingComboBox;
		delete layout;

		DeleteImagePipeline();
	}

	void ConfigureViewerWidget::DeleteImagePipeline()
	{
		// Suppression de toutes les composants de visualisation d'image
		delete imageWidget;  imageWidget = 0;
		delete gradiantWidget; gradiantWidget = 0;
		delete thresholdWidget; thresholdWidget = 0;
		delete refineWidget; refineWidget = 0;		
		delete closeWidget; closeWidget = 0;
		delete modelWidget; modelWidget = 0;
		delete histogramWidget; histogramWidget = 0;

		// Suppression de toutes les images
		delete originalImage; originalImage = 0;
		delete gradiantImage; gradiantImage = 0;
		delete thresholdedImage; thresholdedImage = 0;
		delete refinedImage; refinedImage = 0;
		delete closedImage; closedImage = 0;
		delete gradiantHistogram; gradiantHistogram = 0;
		delete closedOutlineContainer; closedOutlineContainer = 0;		

		// Suppression des contours
		if( modelizedOutlineContainer != 0 )
		{
			ImageAnalysis::SegmentContainer::TSegmentContainerList::iterator outlineIterator;
			for( outlineIterator=modelizedOutlineContainer->begin(); outlineIterator != modelizedOutlineContainer->end(); ++outlineIterator)
			{
				delete *outlineIterator;
			}				
			delete modelizedOutlineContainer; modelizedOutlineContainer = 0;
		}

		// Suppression des masks chargés
		for(int index=0; index < numberOfMask; ++index)
		{
			delete masks[index];
		}
		delete[] masks;
		masks = 0;

		// Suppression des opérateurs de transformations
		delete thresholdOperator; thresholdOperator = 0;
		delete thresholdFinder; thresholdFinder = 0;
		delete refineOperator; refineOperator 	= 0;
		delete convolutionOperator; convolutionOperator = 0;
		delete linkerOperator; linkerOperator 	= 0;
		delete closingOperator; closingOperator = 0;
		delete modelerOperator; modelerOperator = 0;
		numberOfMask = 0;
	}

	ImageAnalysis::GrayImage* ConfigureViewerWidget::LoadImage()
	{

#ifdef QT_VERSION_33
		QString filename = QFileDialog::getOpenFileName( DEFAULT_PATH, "Image Files (*.pgm *.png *.bmp *.jpg)", this, "Open Image", "Choose a file" );
#else
		//QString filename = QFileDialog::getOpenFileName( this, tr("Open Image"), DEFAULT_PATH, tr("Image Files (*.pgm *.png *.bmp *.jpg)"));
		 QString filename = QFileDialog::getOpenFileName(this, tr("Open Image"), "c:\\", tr("Image Files (*.pgm *.png *.jpg *.bmp)"));
#endif
		if ( filename == 0 ) {	return 0; }

		// Chargement de l'image
		ImageAnalysis::GrayImage* grayImage;
		ImageAnalysis::Image* loadedImage;

		ImageAnalysis::OtherImageLoader loader;
#ifdef QT_VERSION_33
		std::string sfilename = filename.ascii();
#else
        	std::string sfilename = filename.toStdString();
#endif	
        	loadedImage = loader.LoadImageFromFile( sfilename );

		// Vérification que l'image est une image en niveaux de gris, sinon conversion
		grayImage = dynamic_cast< ImageAnalysis::GrayImage* >( loadedImage );
		if(  grayImage  == 0 )
		{
			// Conversion de l'image couleur en niveaux de gris
			grayImage = new ImageAnalysis::GrayImage( loadedImage->GetWidth(), loadedImage->GetHeight() );
			ImageAnalysis::ConvertRGBToGrayOperator convertor( dynamic_cast< ImageAnalysis::RGBImage* >( loadedImage ), grayImage );
			convertor.Process();
			delete loadedImage;
		}

		return grayImage;
	}

	ImageAnalysis::Mask** ConfigureViewerWidget::LoadMask()
	{
#ifdef QT_VERSION_33
		QString filename = QFileDialog::getOpenFileName( DEFAULT_PATH, "Mask Files (*.mask)", this, "Open Mask", "Choose a file" );
#else
		QString filename = QFileDialog::getOpenFileName( this, tr("Open Mask"), DEFAULT_PATH, tr("Mask Files (*.mask)"));
#endif

		if ( filename == 0 ) {	return 0; }
#ifdef QT_VERSION_33
		std::string sfilename = filename.ascii();
#else
        	std::string sfilename = filename.toStdString();
#endif
		return ImageAnalysis::MaskTools::LoadMask( sfilename, numberOfMask );
	}

	void ConfigureViewerWidget::CreateImagePipeline()
	{
		// Suppression de tous les composants du pipeline graphique
		DeleteImagePipeline();

		// Creation du pipeline de traitement de l'image
		originalImage 	 = LoadImage(); if( originalImage == 0 ) { return; }
		gradiantImage 	 = new ImageAnalysis::Gradiant( originalImage->GetWidth(),originalImage->GetHeight() );
		thresholdedImage = new ImageAnalysis::BinaryImage( originalImage->GetWidth(),originalImage->GetHeight() );
		refinedImage 	 = new ImageAnalysis::BinaryImage( originalImage->GetWidth(),originalImage->GetHeight() );
		closedImage	 = new ImageAnalysis::RGBImage( originalImage->GetWidth(),originalImage->GetHeight() );

		// Creation des conteneurs contenant les segments
		closedOutlineContainer 	  = new ImageAnalysis::OutlineContainer( originalImage->GetWidth(),originalImage->GetHeight() );
		modelizedOutlineContainer = new ImageAnalysis::SegmentContainer::TSegmentContainerList( );

#ifdef QT_VERSION_33
		int maskType = maskComboBox->currentItem();
#else
	        int maskType = maskComboBox->currentIndex();
#endif
		switch(maskType)
		{
			case ROBERT_MASK :
						masks = ImageAnalysis::MaskTools::BuildRobertsMasks();
						numberOfMask = 2;
						break;
			case PREWITT_MASK :
						masks = ImageAnalysis::MaskTools::BuildPrewittMasks();
						numberOfMask = 2;
						break;
			case SOBEL_MASK :
						masks = ImageAnalysis::MaskTools::BuildSobelMask();
						numberOfMask = 3;
						break;
			case PERSONNAL_MASK :
						masks = LoadMask();
						if( masks == 0 ){ DeleteImagePipeline(); return; }
						break;
			default:break;
		}

		//
		convolutionOperator = new ImageAnalysis::ConvolutionOperator( originalImage, gradiantImage, masks, numberOfMask );

		//
		refineOperator 	= new ImageAnalysis::RefiningOperator( thresholdedImage, gradiantImage, refinedImage);

		// Création du l'operateur de linkage		
		linkerOperator   = new ImageAnalysis::LinkerOperator( gradiantImage, refinedImage, closedOutlineContainer );

#ifdef QT_VERSION_33
		int finderType = thresholdFinderComboBox->currentItem();
#else
        	int finderType = thresholdFinderComboBox->currentIndex();
#endif
		switch(finderType)
		{
			case BASIC_FINDER :
							thresholdFinder = new ImageAnalysis::BasicThresholdFinder();break;
			case ISODATA_FINDER :
							thresholdFinder = new ImageAnalysis::IsoDataThresholdFinder();break;
			case OTSU_FINDER :
							thresholdFinder = new ImageAnalysis::OtsuThresholdFinder();break;
			default:break;
		}

		//

#ifdef QT_VERSION_33
		int thresholdType = thresholdOperatorComboBox->currentItem();
#else
        	int thresholdType = thresholdOperatorComboBox->currentIndex();
#endif
		switch(thresholdType)
		{
			case GLOBAL_THRESHOLD :
							thresholdOperator = new ImageAnalysis::GlobalThresholdOperator(gradiantImage,thresholdedImage,thresholdFinder);break;
			case LOCAL_THRESHOLD :
							thresholdOperator = new ImageAnalysis::LocalThresholdOperator(gradiantImage,thresholdedImage,thresholdFinder, 63 );break;
			case ADAPTIVE_THRESHOLD :
							thresholdOperator = new ImageAnalysis::AdaptativeThresholdOperator(gradiantImage,thresholdedImage,thresholdFinder );break;
			case HYSTERESIS_THRESHOLD :
							thresholdOperator = new ImageAnalysis::HysteresisThresholdOperator(gradiantImage,thresholdedImage, thresholdFinder);break;
			default:break;
		}

#ifdef QT_VERSION_33
		int closingWindowType = closingComboBox->currentItem();
#else
        	int closingWindowType = closingComboBox->currentIndex();
#endif

		switch(closingWindowType)
		{
			case SMALL_CLOSING_WINDOW :
							closingOperator = new ImageAnalysis::OutlineClosingOperator(gradiantImage,closedOutlineContainer,5);break;
			case MEDIUM_CLOSING_WINDOW :
							closingOperator = new ImageAnalysis::OutlineClosingOperator(gradiantImage,closedOutlineContainer,10);break;
			case LARGE_CLOSING_WINDOW :
							closingOperator = new ImageAnalysis::OutlineClosingOperator(gradiantImage,closedOutlineContainer,15);break;
			default:break;
		}

#ifdef QT_VERSION_33
		int modelisationType = modelisingComboBox->currentItem();
#else
        	int modelisationType = modelisingComboBox->currentIndex();
#endif

		switch(modelisationType)
		{
			case POLYGONAL_MODELISATION :
							modelerOperator = new ImageAnalysis::SegmentModelizerOperator( closedOutlineContainer, modelizedOutlineContainer );break;
			case HOUGH_MODELISATION :
							modelerOperator = new ImageAnalysis::HoughTransformationOperator( gradiantImage, refinedImage, modelizedOutlineContainer );break;
			default:break;
		}

		// Création du l'operateur de modelisation
		
		//HoughTransformationOperator houghOperator = new ImageAnalysis::HoughTransformationOperator( gradiantImage, refinedImage );
		//ImageAnalysis::SegmentContainer* segmentContainer = new ImageAnalysis::SegmentContainer( gradiantImage->GetWidth(), gradiantImage->GetHeight() );
		//ImageAnalysis::HoughTransformationOperator houghOperator( gradiantImage, refinedImage, segmentContainer );

		// Lancement des operations du pipeline de traitement d'une image
		convolutionOperator->Process();
		thresholdOperator->Process();
		refineOperator->Process();
		linkerOperator->Process();
		closingOperator->Process();
		modelerOperator->Process();
		
		// Rendu de la fermeture des contours dans une image
		closedOutlineContainer->ImagePrint( closedImage );
		//ImageAnalysis::SegmentContainer::TSegmentContainerList::iterator it;
		//for( it = modelizedOutlineContainer->begin(); it != modelizedOutlineContainer->end(); ++it )
		//{
		//	(*it)->Print( );
		//}	

		

		// Visualisation des images
		imageWidget 	= new LayerViewerWidget( originalImage );
		gradiantWidget 	= new LayerViewerWidget( gradiantImage );
		thresholdWidget = new LayerViewerWidget( thresholdedImage );
		refineWidget 	= new LayerViewerWidget( refinedImage );
		closeWidget 	= new LayerViewerWidget( closedImage );
		modelWidget 	= new SegmentViewerWidget( modelizedOutlineContainer );

		// Creation d'un histogramme pour le gradiant de l'image
		gradiantHistogram = gradiantImage->GetHistogram( 0 );
		histogramWidget   = new HistogramViewerWidget( gradiantHistogram );

		// Visualisation des elements
		histogramWidget->show();
		imageWidget->show();
		gradiantWidget->show();
		thresholdWidget->show();
		refineWidget->show();
		closeWidget->show();
		modelWidget->show();		
	}
